package com.btnc.observer;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import javax.jms.Destination;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.apache.activemq.ActiveMQConnection;
import org.apache.log4j.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

public class TraffyObserverSystem implements MessageListener {
	private static final Logger logger = Logger
			.getLogger(TraffyObserverSystem.class);
	private String connectionURL;

	public String getConnectionURL() {
		return connectionURL;
	}

	public void setConnectionURL(String connectionURL) {
		this.connectionURL = connectionURL;
	}

	@Override
	public void onMessage(Message traffyMessage) {
		if (!(traffyMessage instanceof TextMessage)) {
			logger.error("expected message of type TextMessage, ignoring this message");
			return;
		}
		try {
			String xmlMessage = ((TextMessage) traffyMessage).getText();
			logger.info("received message " + xmlMessage);

			DocumentBuilderFactory builderFactory = DocumentBuilderFactory
					.newInstance();
			DocumentBuilder builder = builderFactory.newDocumentBuilder();
			Document document = builder.parse(new InputSource(new StringReader(
					xmlMessage)));
			NodeList nodes = document.getElementsByTagName("traffy");
			Element element = (Element) nodes.item(0);
			String type = element.getAttribute("type");
			String method = getTextValue(element, "method");

			logger.info("Request for " + method);
			String traffyKey = getTraffyKey();
			String result = "";
			if (method.equals("getIncident")) {
				String limit = getTextValue(element, "limit");
				result = getIncident(traffyKey, limit);
			} else if (method.equals("getCongestionLevel")) {
				String linkId = getTextValue(element, "linkid");
				result = getCL(traffyKey, linkId);
			}

			ActiveMQConnection connection = ActiveMQConnection
					.makeConnection(connectionURL);
			connection.start();
			Session session = connection.createSession(false,
					Session.AUTO_ACKNOWLEDGE);
			Destination output;
			if (type.equals("poller")) {
				output = session.createQueue("traffy.poller.output");
			} else {
				output = session.createQueue("traffy.output");
			}
			MessageProducer producer = session.createProducer(output);
			TextMessage resultMessage = session.createTextMessage();
			resultMessage.setText(result);
			producer.send(resultMessage);
			connection.close();
		} catch (Exception e) {
			logger.error("exception while processing message", e);
		}
	}

	private String getIncident(String traffyKey, String limit) {
		String result = "";
		try {
			URL getLinkUrl = new URL(
					"http://athena.traffy.in.th/apis/apitraffy.php?api=getIncident&key="
							+ traffyKey + "&appid=00001368&limit=" + limit
							+ "&format=XML&type=point");
			URLConnection getLinkCon = getLinkUrl.openConnection();
			BufferedReader linkXML = new BufferedReader(new InputStreamReader(
					getLinkCon.getInputStream()));
			String inputLine;

			while ((inputLine = linkXML.readLine()) != null) {
				logger.debug(inputLine);
				result += inputLine;
			}
			linkXML.close();
		} catch (MalformedURLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return result;
	}

	private String getCL(String traffyKey, String linkId) {
		String result = "";
		try {
			URL getLinkUrl = new URL(
					"http://api.traffy.in.th/apis/apitraffy.php?format=XML&api=getCL&key="
							+ traffyKey + "&appid=00001368&linkid=" + linkId);

			URLConnection getLinkCon = getLinkUrl.openConnection();
			BufferedReader linkXML = new BufferedReader(new InputStreamReader(
					getLinkCon.getInputStream()));
			String inputLine;

			while ((inputLine = linkXML.readLine()) != null) {
				logger.debug(inputLine);
				result += inputLine;
			}
			linkXML.close();
		} catch (MalformedURLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return result;
	}

	private String getTextValue(Element ele, String tagName) {
		String textVal = null;
		NodeList nl = ele.getElementsByTagName(tagName);
		if (nl != null && nl.getLength() > 0) {
			Element el = (Element) nl.item(0);
			textVal = el.getFirstChild().getNodeValue();
		}

		return textVal;
	}

	private String getTraffyKey() {
		// TODO Auto-generated method stub
		String appid = "00001368";
		String keytext = "";
		String hiddenkey = "AibgZsBJdV";
		URL getKeyUrl;
		String passkey = "";
		try {
			getKeyUrl = new URL(
					"http://api.traffy.in.th/apis/getKey.php?appid=" + appid);
			URLConnection getKeyCon = getKeyUrl.openConnection();
			BufferedReader key = new BufferedReader(new InputStreamReader(
					getKeyCon.getInputStream()));

			keytext = key.readLine();

			passkey = encodeString(appid + keytext.trim())
					+ encodeString(hiddenkey + keytext.trim());

		} catch (MalformedURLException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NoSuchAlgorithmException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return passkey;
	}

	public String encodeString(String txt) throws NoSuchAlgorithmException,
			UnsupportedEncodingException {
		// Use MD5
		MessageDigest md;
		md = MessageDigest.getInstance("MD5");
		byte[] md5hash = new byte[32];
		md.update(txt.getBytes("iso-8859-1"), 0, txt.length());
		md5hash = md.digest();
		return convertToHex(md5hash);
	}

	private static String convertToHex(byte[] data) {
		StringBuffer buf = new StringBuffer();
		for (int i = 0; i < data.length; i++) {
			int halfbyte = (data[i] >>> 4) & 0x0F;
			int two_halfs = 0;
			do {
				if ((0 <= halfbyte) && (halfbyte <= 9))
					buf.append((char) ('0' + halfbyte));
				else
					buf.append((char) ('a' + (halfbyte - 10)));
				halfbyte = data[i] & 0x0F;
			} while (two_halfs++ < 1);
		}
		return buf.toString();
	}

}
